﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Collections;
using Utilities;
using System.Drawing.Design;
using ToolMenuBar.Properties;

namespace Ax.Windows.Forms
{
    /// <summary>
    /// 菜单工具栏
    /// </summary>
    public partial class MenuToolBar : Control, IEnumerable
    {
        #region 私有成员
        private bool hover;
        private int hoverIndex;
        private int pressIndex;
        private bool mouseDown;
        private int moreBtnWidth;
        /// <summary>
        /// 实际显示的按钮列表
        /// </summary>
        private MenuToolBtnCollection showBtns;
        #endregion

        #region 公有成员
        [Description("按钮集合"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public MenuToolBtnCollection Btns { get; set; }
        [Description("分割线颜色")]
        public Color SplitLineColor { get; set; }
        [Description("是否显示边线"), DefaultValue(true)]
        public bool ShowBoder { get; set; }
        /// <summary>
        /// 按钮点击事件
        /// </summary>
        [Description("按钮点击事件")]
        public event Action<MenuBtn> OnBtnClicked;
        /// <summary>
        /// 边线颜色
        /// </summary>
        [Description("边线颜色")]
        public Color BoderColor { get; set; }
        /// <summary>
        /// 选中背景色
        /// </summary>
        [Description("选中状态背景色")]
        public Color SelectBackColor { get; set; }
        /// <summary>
        /// 选中按钮字体颜色
        /// </summary>
        [Description("选中状态字体颜色")]
        public Color SelectColor { get; set; }
        private int maxWidth;
        /// <summary>
        /// 按钮宽度
        /// </summary>
        [Description("工具栏能占用的最大长度，0表示不限制长度")]
        public int MaxWidth
        {
            get { return maxWidth; }
            set
            {
                maxWidth = value;
                SyncSize(maxWidth);
            }
        }
        [Description("更多按钮图标")]
        public Image MoreBtnImage { get; set; }
        /// <summary>
        /// 更多按钮
        /// </summary>
        [Browsable(false)]
        [Description("更多按钮")]
        public MenuBtn MoreBtn { get; set; }
        /// <summary>
        /// 该控件按钮是否互斥选中，默认true. 为false时有两种方式: 自动弹回和不自动弹回
        /// </summary>
        [Description("该控件按钮是否互斥选中，默认true. 为false时有两种方式: 自动弹回和不自动弹回"), DefaultValue(true)]
        public bool MutexSelect { get; set; }
        public MenuBtn this[int index]
        {
            get { return Btns[index]; }
        }
        [Browsable(false)]
        public int Count
        {
            get { return Btns.Count; }
        }
        public void Clear()
        {
            Btns.Clear();
        }
        public IEnumerator GetEnumerator()
        {
            return Btns.GetEnumerator();
        }
       
        #endregion

        #region 构造函数
        public MenuToolBar()
        {
            InitializeComponent();
            hoverIndex = -1;
            ShowBoder = true;
            MutexSelect = true;
            ForeColor = Color.Black;
            SelectColor = Color.Black;
            moreBtnWidth = 68;
            Btns = new MenuToolBtnCollection();
            MoreBtnImage = Resources.more;
            Btns.MenuToolBar = this;
            showBtns = new MenuToolBtnCollection();
            BackColor = Color.FromArgb(241, 241, 241);
            BoderColor = Color.FromArgb(201, 201, 201);
            SplitLineColor = Color.FromArgb(222, 222, 222);
            SelectBackColor = Color.FromArgb(220, 220, 220);
            Font = new Font("微软雅黑", 9, FontStyle.Regular);
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
        }
        #endregion

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            SyncSize(Width);
            CalcBtnBounds();
        }

        public void CalcBtnBounds()
        {
            int width = 0;
            foreach (BaseBtn btn in Btns)
            {
                btn.Bounds = new Rectangle(width, 0, btn.Width, Height);
                width += btn.Width;
            }
        }

        #region 重绘函数
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            foreach (MenuBtn btn in showBtns)
            {
                DrawBtn(e.Graphics, btn);
            }
            if (ShowBoder)
            {
                using (Pen iPen = new Pen(BoderColor))
                    e.Graphics.DrawRectangle(iPen, 0, 0, Width - 1, Height - 1);
            }
        }

        private void DrawBtn(Graphics g, MenuBtn btn)
        {
            bool enabled = Enabled && btn.Enabled;
            //绘制选中按钮背景色
            if (enabled && (btn.Checked || btn.Pressed) && btn.EventResponse)
            {
                using (Brush iBrush = new SolidBrush(SelectBackColor))
                {
                    g.FillRectangle(iBrush, btn.Bounds);
                    iBrush.Dispose();
                }
            }
            //绘制按钮分割线
            using (Pen iPen = new Pen(SplitLineColor))
            {
                g.DrawLine(iPen, new Point(btn.Bounds.Left, btn.Bounds.Y), new Point(btn.Bounds.Left, btn.Bounds.Bottom));
                iPen.Dispose();
            }
            //绘制图片和文字
            if (btn.ImageOnly)
            {
                if (btn.Image != null)
                {
                    int width = (btn.Width - btn.Image.Width) / 2;
                    Point pt = new Point(btn.Bounds.Left + width, (Height - btn.Image.Height) / 2);
                    g.DrawImage(btn.Image, new Rectangle(pt, new Size(btn.Image.Width, btn.Image.Height)));
                }
            }
            else
            {
                Point offset = (mouseDown && btn.Enabled && btn.Pressed && btn.EventResponse) ? new Point(1, 1) : Point.Empty;
                Color txtColor = enabled ? (btn.Checked || btn.Pressed) ? SelectColor : ForeColor : Color.FromArgb(160, 160, 160);
                using (Brush iBrush = new SolidBrush(txtColor))
                {
                    Size textSize = TextRenderer.MeasureText(btn.Text, Font);
                    if (btn.Image == null && btn.Btns.Count == 0)
                    {
                        Point pt = new Point((btn.Width - textSize.Width) / 2 + btn.Bounds.Left + 2, (Height - textSize.Height) / 2);
                        pt.Offset(offset);
                        g.DrawString(btn.Text, Font, iBrush, pt);
                    }
                    else
                    {
                        Image showImage = GetBtnImage(btn, enabled);
                        int startPosX = btn.Bounds.Left + offset.X + (btn.Width - (showImage.Width + textSize.Width)) / 2;
                        int startPosY = (Height - showImage.Height) / 2 + offset.Y;
                        if (btn.ImageFirst && btn.Btns.Count == 0)
                        {
                            g.DrawImage(showImage, new Rectangle(startPosX, startPosY, showImage.Width, showImage.Height));
                            g.DrawString(btn.Text, Font, iBrush, new Point(startPosX + showImage.Width, (Height - textSize.Height) / 2 + offset.Y));
                        }
                        else
                        {
                            g.DrawString(btn.Text, Font, iBrush, new Point(startPosX, startPosY));
                            g.DrawImage(showImage, new Rectangle(startPosX + textSize.Width, startPosY, showImage.Width, showImage.Height));
                        }
                    }
                    iBrush.Dispose();
                }
            }
        }

        private Image GetBtnImage(MenuBtn btn, bool enabled)
        {
            Image showImage;
            if (btn.Btns.Count > 0)
                showImage = enabled ? MoreBtnImage : DrawHelper.ChangeImageColor(MoreBtnImage);
            else
                showImage = enabled ? btn.Image : DrawHelper.ChangeImageColor(btn.Image);
            return showImage;
        }
        #endregion
        bool isShow;
        #region 鼠标响应事件
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (hover)
            {
                int index = GetIndex(e.X);
                if (index != hoverIndex)
                {
                    if (index < showBtns.Count && index >= 0)
                    {
                        hoverIndex = index;
                        if (!string.IsNullOrEmpty(showBtns[hoverIndex].Tips))
                            toolTipEx.Show(showBtns[hoverIndex].Tips, this, showBtns[hoverIndex].Bounds.Left, -17 * GetEnterNum(showBtns[hoverIndex].Tips) - 6);
                        else
                            toolTipEx.Hide(this);
                    }
                }
            }
        }

        int GetEnterNum(string str)
        {
            int num = 1;
            foreach (var c in str)
            {
                if (c == 13)
                {
                    num++;
                }
            }
            return num;
        }

        protected override void OnMouseHover(EventArgs e)
        {
            base.OnMouseHover(e);
            hover = true;
            if (hoverIndex >= 0 && showBtns.Count > hoverIndex && !string.IsNullOrEmpty(showBtns[hoverIndex].Tips))
                toolTipEx.Show(showBtns[hoverIndex].Tips, this, showBtns[hoverIndex].Bounds.Left, -17 * GetEnterNum(showBtns[hoverIndex].Tips) - 6);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            hover = false;
            toolTipEx.Hide(this);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left)
            {
                mouseDown = true;
                pressIndex = GetIndex(e.X);
                showBtns[pressIndex].Pressed = true;
                this.Invalidate();
            }
        }

        private int GetIndex(int mouseX)
        {
            int index = -1;
            for (int i = 0; i < showBtns.Count; i++)
            {
                if (mouseX <= showBtns[i].Bounds.Right)
                {
                    return i;
                }
            }
            return index;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (e.Button == MouseButtons.Left)
            {
                mouseDown = false;
                if (pressIndex >= 0 && pressIndex < showBtns.Count)
                    showBtns[pressIndex].Pressed = false;
                int index = GetIndex(e.X);
                if (index >= 0)
                {
                    MenuBtn btn = showBtns[index];
                    if (btn.EventResponse && e.Y >= 0 && e.Y < Height)
                    {
                        BtnOnClicked(btn);
                        if (btn.Btns.Count > 0)
                        {
                            btn.ShowMenu(this, PointToScreen(new Point(GetToolBarWidth(showBtns, index), Height)));
                        }
                        else if (!btn.ImageOnly)
                        {
                            if (MutexSelect)
                            {
                                foreach (MenuBtn bt in Btns)
                                {
                                    bt.Checked = false;
                                }
                                btn.Checked = true;
                            }
                            else
                            {
                                if (btn.AutoRebound)
                                    btn.Checked = false;
                                else
                                    btn.Checked = !btn.Checked;
                            }
                        }
                    }
                }
                Invalidate();
            }
        }
        #endregion

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            SyncSize(Size.Width);
        }

        public void ClearCheckd()
        {
            foreach (BaseBtn btn in Btns)
            {
                btn.Checked = false;
            }
            Invalidate();
        }

        public void BtnOnClicked(MenuBtn btn)
        {
            if (OnBtnClicked != null)
            {
                OnBtnClicked(btn);
            }
        }

        /// <summary>
        /// 改变宽度时重新计算显示的按钮数量
        /// </summary>
        /// <param name="length"></param>
        public void SyncSize(int length = 0)
        {
            if (Btns == null) return;
            if (length == 0)
            {
                if (Btns.Count > 0)
                {
                    this.Width = GetToolBarWidth(Btns);
                }
            }
            else
            {
                bool folded = length < GetToolBarWidth(Btns);
                int showNum = Btns.Count;
                int w = folded ? moreBtnWidth : 0;
                for (int i = 0; i < Btns.Count;i++)
                {
                    w += Btns[i].Width;
                    if (w > length)
                    {
                        showNum = i;
                        break;
                    }
                }
                showBtns.Clear();
                for (int i = 0; i < showNum; i++)
                {
                    showBtns.Add(Btns[i]);
                }
                //如果折叠,添加更多按钮
                if (folded && showNum >= 0)
                {
                    AddMoreBtn(showNum);
                }
                if(showBtns.Count > 0)
                {
                    this.Width = GetToolBarWidth(showBtns);
                }
            }
            this.Invalidate();
        }

        private int GetToolBarWidth(MenuToolBtnCollection btnList, int index = -1)
        {
            int w = 0;
            int length = index == -1 ? btnList.Count : index;
            for (int i = 0; i < length; i++)
            {
                w += btnList[i].Width;
            }
            return w;
        }

        void AddMoreBtn(int showNum)
        {
            MenuBtn btn = new MenuBtn(this);
            btn.BtnClicked += BtnOnClicked;
            for (int i = showNum; i < Btns.Count; i++)
            {
                btn.AddChild(Btns[i]);
            }
            btn.Text = "更多";
            btn.Name = "More";
            int width = 0;
            for (int i = 0; i < showNum; i++)
            {
                width += Btns[i].Width;
            }
            btn.Width = moreBtnWidth;
            btn.Bounds = new Rectangle(width, 0, moreBtnWidth, Height);
            showBtns.Add(btn);
            MoreBtn = btn;
        }
    }

    [Editor(typeof(BtnCollectionEditor), typeof(UITypeEditor))]
    public class MenuToolBtnCollection : CollectionBase
    {
        public MenuBtn Owner;
        public MenuToolBar MenuToolBar;

        public MenuBtn this[int index]
        {
            get
            {
                if (index >= 0 && index < List.Count)
                    return ((MenuBtn)List[index]);
                return null;
            }
            set { List[index] = value; }
        }

        public MenuBtn this[string name]
        {
            get
            {
                foreach (MenuBtn item in this.List)
                {
                    if (item.Name == name) return item;
                }
                return null;
            }
        }

        public int Add(MenuBtn value)
        {
            return List.Add(value);
        }


        public int IndexOf(MenuBtn value)
        {
            return List.IndexOf(value);
        }

        public void Insert(int index, MenuBtn value)
        {
            List.Insert(index, value);
        }

        public void Remove(MenuBtn value)
        {
            List.Remove(value);
        }

        public bool Contains(MenuBtn value)
        {
            return (List.Contains(value));
        }

        public new void Clear()
        {
            this.List.Clear();
        }

        protected override void OnInsertComplete(int index, object value)
        {
            base.OnInsertComplete(index, value);
            var btn = value as MenuBtn;
            if (MenuToolBar != null)
            {
                btn.ToolBar = MenuToolBar;
                btn.BtnClicked += MenuToolBar.BtnOnClicked;
                MenuToolBar.CalcBtnBounds();
                MenuToolBar.SyncSize(MenuToolBar.MaxWidth);
            }
        }

        protected override void OnRemove(int index, object value)
        {
            base.OnRemove(index, value);
        }
    }
}
